using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using Max.Domain.Mapping;
using Max.Domain.Mapping.Implementation;
using Ordering.Service.Contract;

namespace Ordering.Service.Application
{
    public static partial class GeneratedMapperExtensions
    {
        #region Mapper extensions for CustomerItem

        public static Collection<CustomerItem> MapToCustomerItemCollection(this Mapper mapper, IEnumerable<Ordering.BusinessLayer.Customer> source)
        {
            Collection<CustomerItem> target = new Collection<CustomerItem>();
            foreach(var item in source) target.Add(mapper.MapToCustomerItem(item));
            return target;
        }

        public static CustomerItem MapToCustomerItem(this Mapper mapper, Ordering.BusinessLayer.Customer source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapToCustomerItem(source, new CustomerItem());
        }
        
        internal static CustomerItem MapToCustomerItem(this Mapper mapper, Ordering.BusinessLayer.Customer source, CustomerItem target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            var mappedTarget = mapper.GetMappedTarget<CustomerItem>(source);
            
            // If so, return mapped instance:
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return mappedTarget;

            // Else, register mapping and map target:
            mapper.RegisterMapping(source, target);
            mapper.UpdateCustomerItem(source, target);
            
            // Return mapped target:
            return target;
        }
        
        internal static void UpdateCustomerItem(this Mapper mapper, Ordering.BusinessLayer.Customer source, CustomerItem target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map CustomerItem on.");

            // Perform base type mapping:
            mapper.UpdateSystemObject(source, target);

            // Perform mapping of properties:
            target.Id = source.Id;
            target.Name = source.Name;
            target.Email = source.Email;
            target.Address = source.Address;

            // Call partial AfterUpdate method:
            AfterUpdateCustomerItem(mapper, source, target);
        }

        static partial void AfterUpdateCustomerItem(this Mapper mapper, Ordering.BusinessLayer.Customer source, CustomerItem target);

        #endregion

        #region Mapper extensions for OrderDetail

        public static Collection<OrderDetail> MapToOrderDetailCollection(this Mapper mapper, IEnumerable<Ordering.BusinessLayer.Order> source)
        {
            Collection<OrderDetail> target = new Collection<OrderDetail>();
            foreach(var item in source) target.Add(mapper.MapToOrderDetail(item));
            return target;
        }

        public static OrderDetail MapToOrderDetail(this Mapper mapper, Ordering.BusinessLayer.Order source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapToOrderDetail(source, new OrderDetail());
        }
        
        internal static OrderDetail MapToOrderDetail(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderDetail target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            var mappedTarget = mapper.GetMappedTarget<OrderDetail>(source);
            
            // If so, return mapped instance:
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return mappedTarget;

            // Else, register mapping and map target:
            mapper.RegisterMapping(source, target);
            mapper.UpdateOrderDetail(source, target);
            
            // Return mapped target:
            return target;
        }
        
        internal static void UpdateOrderDetail(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderDetail target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map OrderDetail on.");

            // Perform base type mapping:
            mapper.UpdateSystemObject(source, target);

            // Perform mapping of properties:
            target.OrderNumber = source.Id;
            target.OrderDate = source.OrderDate;
            target.Customer = mapper.MapToCustomerItem(source.Customer);
            foreach(var item in source.OrderLines) target.OrderLines.Add(mapper.MapToOrderLineDetail((Ordering.BusinessLayer.OrderLine)item));

            // Call partial AfterUpdate method:
            AfterUpdateOrderDetail(mapper, source, target);
        }

        static partial void AfterUpdateOrderDetail(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderDetail target);

        #endregion

        #region Mapper extensions for OrderItem

        public static Collection<OrderItem> MapToOrderItemCollection(this Mapper mapper, IEnumerable<Ordering.BusinessLayer.Order> source)
        {
            Collection<OrderItem> target = new Collection<OrderItem>();
            foreach(var item in source) target.Add(mapper.MapToOrderItem(item));
            return target;
        }

        public static OrderItem MapToOrderItem(this Mapper mapper, Ordering.BusinessLayer.Order source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapToOrderItem(source, new OrderItem());
        }
        
        internal static OrderItem MapToOrderItem(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            var mappedTarget = mapper.GetMappedTarget<OrderItem>(source);
            
            // If so, return mapped instance:
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return mappedTarget;

            // Else, register mapping and map target:
            mapper.RegisterMapping(source, target);
            mapper.UpdateOrderItem(source, target);
            
            // Return mapped target:
            return target;
        }
        
        internal static void UpdateOrderItem(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map OrderItem on.");

            // Perform base type mapping:
            mapper.UpdateSystemObject(source, target);

            // Perform mapping of properties:
            target.OrderNumber = source.Id;
            target.OrderDate = source.OrderDate;
            target.CustomerId = source.CustomerId;
            target.TotalOrderPrice = source.TotalOrderPrice;
            mapper.MapOrderItemCustomerNameProperty(source, target);
            mapper.MapOrderItemProductIdsProperty(source, target);
            mapper.MapOrderItemProductLabelsProperty(source, target);

            // Call partial AfterUpdate method:
            AfterUpdateOrderItem(mapper, source, target);
        }

        static partial void AfterUpdateOrderItem(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target);


        static void MapOrderItemCustomerNameProperty(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target)
        {
            do
            {
                var item0 = source;
                var item1 = item0.Customer;
                if (item1 == null) break;
                var item2 = item1.Name;
                target.CustomerName = item2;
            } while (false);
        }

        static void MapOrderItemProductIdsProperty(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target)
        {
            do
            {
                var item0 = source;
                foreach(var item1 in item0.OrderLines)
                {
                    var item2 = item1.ProductId;
                    target.ProductIds.Add(item2);
                }
            } while (false);
        }

        static void MapOrderItemProductLabelsProperty(this Mapper mapper, Ordering.BusinessLayer.Order source, OrderItem target)
        {
            do
            {
                var item0 = source;
                foreach(var item1 in item0.OrderLines)
                {
                    var item2 = item1.Product;
                    if (item2 == null) break;
                    var item3 = item2.Label;
                    target.ProductLabels.Add(item3);
                }
            } while (false);
        }
        #endregion

        #region Mapper extensions for OrderLineDetail

        public static Collection<OrderLineDetail> MapToOrderLineDetailCollection(this Mapper mapper, IEnumerable<Ordering.BusinessLayer.OrderLine> source)
        {
            Collection<OrderLineDetail> target = new Collection<OrderLineDetail>();
            foreach(var item in source) target.Add(mapper.MapToOrderLineDetail(item));
            return target;
        }

        public static OrderLineDetail MapToOrderLineDetail(this Mapper mapper, Ordering.BusinessLayer.OrderLine source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapToOrderLineDetail(source, new OrderLineDetail());
        }
        
        internal static OrderLineDetail MapToOrderLineDetail(this Mapper mapper, Ordering.BusinessLayer.OrderLine source, OrderLineDetail target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            var mappedTarget = mapper.GetMappedTarget<OrderLineDetail>(source);
            
            // If so, return mapped instance:
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return mappedTarget;

            // Else, register mapping and map target:
            mapper.RegisterMapping(source, target);
            mapper.UpdateOrderLineDetail(source, target);
            
            // Return mapped target:
            return target;
        }
        
        internal static void UpdateOrderLineDetail(this Mapper mapper, Ordering.BusinessLayer.OrderLine source, OrderLineDetail target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map OrderLineDetail on.");

            // Perform base type mapping:
            mapper.UpdateSystemObject(source, target);

            // Perform mapping of properties:
            target.Id = source.Id;
            target.Product = mapper.MapToProductItem(source.Product);
            target.UnitPrice = source.UnitPrice;
            target.Quantity = source.Quantity;

            // Call partial AfterUpdate method:
            AfterUpdateOrderLineDetail(mapper, source, target);
        }

        static partial void AfterUpdateOrderLineDetail(this Mapper mapper, Ordering.BusinessLayer.OrderLine source, OrderLineDetail target);

        #endregion

        #region Mapper extensions for ProductItem

        public static Collection<ProductItem> MapToProductItemCollection(this Mapper mapper, IEnumerable<Ordering.BusinessLayer.Product> source)
        {
            Collection<ProductItem> target = new Collection<ProductItem>();
            foreach(var item in source) target.Add(mapper.MapToProductItem(item));
            return target;
        }

        public static ProductItem MapToProductItem(this Mapper mapper, Ordering.BusinessLayer.Product source)
        {
            if (source == null)
                return null;
            else
                return mapper.MapToProductItem(source, new ProductItem());
        }
        
        internal static ProductItem MapToProductItem(this Mapper mapper, Ordering.BusinessLayer.Product source, ProductItem target)
        {
            // Null maps to null:
            if (source == null) return null;

            // Check if object already mapped (as in circular reference scenarios):
            var mappedTarget = mapper.GetMappedTarget<ProductItem>(source);
            
            // If so, return mapped instance:
            if (Object.ReferenceEquals(mappedTarget, null) == false)
                return mappedTarget;

            // Else, register mapping and map target:
            mapper.RegisterMapping(source, target);
            mapper.UpdateProductItem(source, target);
            
            // Return mapped target:
            return target;
        }
        
        internal static void UpdateProductItem(this Mapper mapper, Ordering.BusinessLayer.Product source, ProductItem target)
        {
            // Verify null args:
            if (Object.ReferenceEquals(source, null))
                return;
            else if (Object.ReferenceEquals(target, null))
                throw new Max.Domain.Mapping.MappingException("No target provided to map ProductItem on.");

            // Perform base type mapping:
            mapper.UpdateSystemObject(source, target);

            // Perform mapping of properties:
            target.Id = source.Id;
            target.Label = source.Label;
            target.Description = source.Description;
            target.SalePrice = source.SalePrice;

            // Call partial AfterUpdate method:
            AfterUpdateProductItem(mapper, source, target);
        }

        static partial void AfterUpdateProductItem(this Mapper mapper, Ordering.BusinessLayer.Product source, ProductItem target);

        #endregion

    }
}